﻿using System;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using AnthStat.WPF.Applications;

namespace AnthStat.WPF.Presentation.Controls
{
    public sealed partial class IndicatorChartControl : ItemsControl
    {
        static IndicatorChartControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(IndicatorChartControl), new FrameworkPropertyMetadata(typeof(IndicatorChartControl)));
        }

        #region Properties

        public static readonly DependencyProperty ShowsInPercentilesProperty =
            DependencyProperty.RegisterAttached("ShowsInPercentiles",
                 typeof(bool),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty YAxisStartValueProperty =
            DependencyProperty.RegisterAttached("YAxisStartValue",
                 typeof(double),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty XAxisStartValueProperty =
            DependencyProperty.RegisterAttached("XAxisStartValue",
                 typeof(double),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty YAxisEndValueProperty =
            DependencyProperty.RegisterAttached("YAxisEndValue",
                 typeof(double),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty XAxisEndValueProperty =
            DependencyProperty.RegisterAttached("XAxisEndValue",
                 typeof(double),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(Double.NaN, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty GrowthReferenceProperty =
            DependencyProperty.RegisterAttached("GrowthReference",
                 typeof(string),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata("WHO", FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty XAxisLabelProperty =
            DependencyProperty.RegisterAttached("XAxisLabel",
                 typeof(string),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty YAxisLabelProperty =
            DependencyProperty.RegisterAttached("YAxisLabel",
                 typeof(string),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty YAxisPathProperty =
            DependencyProperty.RegisterAttached("YAxisPath",
                 typeof(string),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(String.Empty));

        public static readonly DependencyProperty XAxisPathProperty =
            DependencyProperty.RegisterAttached("XAxisPath",
                 typeof(string),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(String.Empty));

        public static readonly DependencyProperty ShowMinorGridLinesProperty =
            DependencyProperty.RegisterAttached("ShowMinorGridLines",
                 typeof(bool),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(true));

        public static readonly DependencyProperty YAxisStepValueProperty =
            DependencyProperty.RegisterAttached("YAxisStepValue",
                 typeof(double),
                 typeof(IndicatorChartControl),
                 new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public bool ShowsInPercentiles
        {
            get { return (bool)GetValue(ShowsInPercentilesProperty); }
            set { SetValue(ShowsInPercentilesProperty, value); }
        }

        public double YAxisStartValue
        {
            get { return (double)GetValue(YAxisStartValueProperty); }
            set { SetValue(YAxisStartValueProperty, value); }
        }

        public double XAxisStartValue
        {
            get { return (double)GetValue(XAxisStartValueProperty); }
            set { SetValue(XAxisStartValueProperty, value); }
        }

        public double YAxisEndValue
        {
            get { return (double)GetValue(YAxisEndValueProperty); }
            set { SetValue(YAxisEndValueProperty, value); }
        }

        public double XAxisEndValue
        {
            get { return (double)GetValue(XAxisEndValueProperty); }
            set { SetValue(XAxisEndValueProperty, value); }
        }

        public string GrowthReference
        {
            get { return GetValue(GrowthReferenceProperty).ToString(); }
            set { SetValue(GrowthReferenceProperty, value); }
        }

        public string XAxisLabel
        {
            get { return GetValue(XAxisLabelProperty).ToString(); }
            set { SetValue(XAxisLabelProperty, value); }
        }

        public string YAxisLabel
        {
            get { return GetValue(YAxisLabelProperty).ToString(); }
            set { SetValue(YAxisLabelProperty, value); }
        }

        public string YAxisPath
        {
            get { return GetValue(YAxisPathProperty).ToString(); }
            set { SetValue(YAxisPathProperty, value); }
        }

        public string XAxisPath
        {
            get { return GetValue(XAxisPathProperty).ToString(); }
            set { SetValue(XAxisPathProperty, value); }
        }

        public bool ShowMinorGridLines
        {
            get { return (bool)GetValue(ShowMinorGridLinesProperty); }
            set { SetValue(ShowMinorGridLinesProperty, value); }
        }

        public double YAxisStepValue
        {
            get { return (double)GetValue(YAxisStepValueProperty); }
            set { SetValue(YAxisStepValueProperty, value); }
        }

        #endregion // Properties

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);

            if (e.Property.Name == "DataContext" || 
                e.Property.Name == "ActualWidth" || 
                e.Property.Name == "ActualHeight" || 
                e.Property.Name.Equals("GrowthReference", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("XAxisStartValue", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("XAxisEndValue", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("YAxisStartValue", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("YAxisEndValue", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("YAxisPath", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("XAxisPath", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("YAxisStepValue", StringComparison.OrdinalIgnoreCase) ||
                e.Property.Name.Equals("ShowsInPercentiles", StringComparison.OrdinalIgnoreCase)
                )
            {
                OnApplyTemplate();
            }
        }

        private void AddStaticLine(Canvas canvas, SolidColorBrush lineBrush, double X1, double X2, double Y1, double Y2)
        {
            Contract.Requires(canvas != null);

            Line line = new Line();
            line.StrokeThickness = 1;

            line.Stroke = lineBrush;

            line.X1 = X1;
            line.Y2 = Y2;

            line.X2 = X2;
            line.Y1 = Y1;

            Canvas.SetLeft(line, 0);
            Canvas.SetBottom(line, Math.Min(line.Y1, line.Y2));
            canvas.Children.Add(line);
        }

        private void DrawCDCPercentileCurves()
        {
            PersonViewModel vm = DataContext as PersonViewModel;

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;

            if (vm != null && canvas != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));
                double[,] data = MaleCDCBMIData;

                if (YAxisPath.ToString().Equals("BodyMassIndex"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleCDCBMIData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleCDCBMIData;
                    }
                }
                else if (YAxisPath.ToString().Equals("Weight"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleCDCWAData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleCDCWAData;
                    }
                }
                else if (YAxisPath.ToString().Equals("HeadCircumference"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleCDCHCData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleCDCHCData;
                    }
                }
                else
                {
                    return;
                }

                for (int j = 2; j < 10; j++)
                {
                    PathFigure figure = new PathFigure();

                    PolyBezierSegment bezierSegment = new PolyBezierSegment();

                    bool first = true;

                    for (int i = 0; i < (data.Length / data.GetLength(1)) - 1; i++)
                    {
                        double staticAge = (data[i, 0] / 12);

                        if (staticAge >= (double)GetValue(XAxisStartValueProperty) && staticAge <= (double)GetValue(YAxisEndValueProperty))
                        {
                            staticAge = staticAge - XAxisStartValue;
                            double staticBodyMassIndex = data[i, j] - YAxisStartValue;

                            if (i == 0 || first)
                            {
                                figure.StartPoint = new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio));
                                first = false;
                            }

                            bezierSegment.Points.Add(new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio)));

                            if (i == (data.Length / data.GetLength(1)) - 2)
                            {
                                TextBlock tb = new TextBlock();
                                tb.FontSize = 12;

                                switch (j)
                                {
                                    case 2:
                                        tb.Text = "5th";
                                        break;
                                    case 3:
                                        tb.Text = "10th";
                                        break;
                                    case 4:
                                        tb.Text = "25th";
                                        break;
                                    case 5:
                                        tb.Text = "50th";
                                        break;
                                    case 6:
                                        tb.Text = "75th";
                                        break;
                                    case 7:
                                        tb.Text = "85th";
                                        break;
                                    case 8:
                                        tb.Text = "90th";
                                        break;
                                    case 9:
                                        tb.Text = "95th";
                                        break;
                                }

                                Canvas.SetLeft(tb, staticAge * widthRatio);
                                Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 5);
                                canvas.Children.Add(tb);
                            }
                        }
                    }


                    //figure.StartPoint = new Point(0, 500);
                    figure.Segments = new PathSegmentCollection();
                    figure.Segments.Add(bezierSegment);

                    PathFigureCollection pathCollection = new PathFigureCollection();
                    pathCollection.Add(figure);

                    PathGeometry geometry = new PathGeometry(pathCollection);

                    Path path = new Path();
                    path.Data = geometry;

                    path.Stroke = Brushes.Black;

                    if (j == 5)
                    {
                        //path.Stroke = Brushes.ForestGreen;
                        path.StrokeThickness = 2;
                    }
                    else if (j == 2 || j == 7 || j == 9)
                    {
                        
                        path.StrokeThickness = 2;
                    }
                    else
                    {
                        path.StrokeThickness = 1;
                    }

                    path.Width = canvas.ActualWidth;
                    path.Height = canvas.ActualHeight;

                    Canvas.SetLeft(path, 0);
                    Canvas.SetTop(path, 0);
                    canvas.Children.Add(path);
                }
            }
        }

        private void DrawWHO2006PercentileCurves()
        {
            PersonViewModel vm = DataContext as PersonViewModel;

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;

            if (vm != null && canvas != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));
                double[,] data = MaleWHOBMIData;

                if (YAxisPath.ToString().Equals("BodyMassIndex"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHOBMIData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHOBMIData;
                    }
                }
                else if (YAxisPath.ToString().Equals("Height"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006HAData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006HAData;
                    }
                }
                else if (YAxisPath.ToString().Equals("Weight"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006WAData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006WAData;
                    }
                }
                else if (YAxisPath.ToString().Equals("HeadCircumference"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006HCData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006HCData;
                    }
                }
                else if (YAxisPath.ToString().Equals("MidUpperArmCircumference"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006ACData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006ACData;
                    }
                }
                else
                {
                    return;
                }

                for (int j = 3; j < 14; j++)
                {
                    if (j == 4 || j == 5 || j == 7 || j == 9 || j == 11 || j == 12) continue;

                    var figure = new PathFigure();

                    var bezierSegment = new PolyBezierSegment();

                    bool first = true;

                    for (int i = 0; i < (data.Length / data.GetLength(1)) - 1; i++)
                    {
                        double staticAge;
                        
                        //if(data.GetLength(1) == 8) 
                        //{
                        //    staticAge = (data[i, 0] / 12); 
                        //}
                        //else 
                        //{
                            staticAge = (data[i, 0] * 0.00273785);
                        //}

                        if (staticAge >= (double)GetValue(XAxisStartValueProperty) && staticAge <= (double)GetValue(YAxisEndValueProperty))
                        {
                            staticAge = staticAge - XAxisStartValue;
                            double staticBodyMassIndex = data[i, j] - YAxisStartValue;

                            if (i == 0 || first)
                            {
                                figure.StartPoint = new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio));
                                first = false;
                            }

                            bezierSegment.Points.Add(new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio)));

                            if (YAxisPath.ToString().Equals("HeadCircumference") || YAxisPath.ToString().Equals("MidUpperArmCircumference"))
                            {
                                if (i == (data.Length / data.GetLength(1)) - 2)
                                {
                                    TextBlock tb = new TextBlock();
                                    tb.FontSize = 12;

                                    switch (j)
                                    {
                                        case 2:
                                            tb.Text = "1st";
                                            break;
                                        case 3:
                                            tb.Text = "3rd";
                                            break;
                                        case 6:
                                            tb.Text = "15th";
                                            break;
                                        case 8:
                                            tb.Text = "50th";
                                            break;
                                        case 10:
                                            tb.Text = "85th";
                                            break;
                                        case 13:
                                            tb.Text = "97th";
                                            break;
                                        case 14:
                                            tb.Text = "99th";
                                            break;
                                    }

                                    Canvas.SetLeft(tb, (staticAge * widthRatio) + 5);
                                    Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 4);
                                    canvas.Children.Add(tb);
                                }
                            }
                        }
                    }

                    figure.Segments = new PathSegmentCollection();
                    figure.Segments.Add(bezierSegment);

                    var pathCollection = new PathFigureCollection();
                    pathCollection.Add(figure);

                    var geometry = new PathGeometry(pathCollection);

                    var path = new Path();
                    path.Data = geometry;

                    //if (data.GetLength(1) != 8)
                    //{
                        if (j == 8)
                        {
                            path.StrokeThickness = 2;
                            path.Stroke = Brushes.ForestGreen;
                        }
                        else
                        {
                            path.StrokeThickness = 1.5;
                            path.Stroke = Brushes.Black;

                            if (j == 3 || j == 13) path.Stroke = Brushes.Tomato;
                            if (j == 6 || j == 10) path.Stroke = Brushes.Gold;
                        }
                    //}
                    //else
                    //{
                    //    if (j == 4)
                    //    {
                    //        path.StrokeThickness = 2;
                    //        path.Stroke = Brushes.ForestGreen;
                    //    }
                    //    else
                    //    {
                    //        path.StrokeThickness = 1.5;
                    //        path.Stroke = Brushes.Black;

                    //        if (j == 2 || j == 6) path.Stroke = Brushes.Tomato;
                    //        if (j == 3 || j == 5) path.Stroke = Brushes.Gold;
                    //    }
                    //}

                    path.Width = canvas.ActualWidth;
                    path.Height = canvas.ActualHeight;

                    Canvas.SetLeft(path, 0);
                    Canvas.SetTop(path, 0);
                    canvas.Children.Add(path);
                }
            }
        }

        private void DrawWHO2007PercentileCurves()
        {
            PersonViewModel vm = DataContext as PersonViewModel;

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;

            if (vm != null && canvas != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));
                double[,] data = MaleWHO2007BMIData;

                if (YAxisPath.ToString().Equals("BodyMassIndex"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007BMIData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007BMIData;
                    }
                }
                else if (YAxisPath.ToString().Equals("Height"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007HAData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007HAData;
                    }
                }
                else if (YAxisPath.ToString().Equals("Weight"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007WAData;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007WAData;
                    }
                }
                else
                {
                    return;
                }

                //if (vm.Sex == "F")
                //{
                //    bmiData = FemaleWHO2007BMIData;
                //}

                for (int j = 3; j < 14; j++)
                {
                    if (j == 4 || j == 5 || j == 7 || j == 9 || j == 11 || j == 12)
                    {
                        continue;
                    }

                    var figure = new PathFigure();

                    var bezierSegment = new PolyBezierSegment();

                    bool first = true;

                    for (int i = 0; i < (data.Length / 16) - 1; i++)
                    {
                        double staticAge = (data[i, 0] / 12);

                        if (staticAge >= (double)GetValue(XAxisStartValueProperty) && staticAge <= (double)GetValue(YAxisEndValueProperty))
                        {
                            staticAge = staticAge - XAxisStartValue;
                            double staticBodyMassIndex = data[i, j] - YAxisStartValue;

                            if (i == 0 || first)
                            {
                                figure.StartPoint = new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio));
                                first = false;
                            }

                            bezierSegment.Points.Add(new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio)));

                            if (i == (data.Length / 16) - 2)
                            {
                                var tb = new TextBlock { FontSize = 12 };

                                switch (j)
                                {
                                    case 1:
                                        tb.Text = "0.1st";
                                        break;
                                    case 2:
                                        tb.Text = "1st";
                                        break;
                                    case 3:
                                        tb.Text = "3rd";
                                        break;
                                    case 4:
                                        tb.Text = "5th";
                                        break;
                                    case 5:
                                        tb.Text = "10th";
                                        break;
                                    case 6:
                                        tb.Text = "15th";
                                        break;
                                    case 7:
                                        tb.Text = "25th";
                                        break;
                                    case 8:
                                        tb.Text = "50th";
                                        break;
                                    case 9:
                                        tb.Text = "75th";
                                        break;
                                    case 10:
                                        tb.Text = "85th";
                                        break;
                                    case 11:
                                        tb.Text = "90th";
                                        break;
                                    case 12:
                                        tb.Text = "95th";
                                        break;
                                    case 13:
                                        tb.Text = "97th";
                                        break;
                                    case 14:
                                        tb.Text = "99th";
                                        break;
                                    case 15:
                                        tb.Text = "99.9th";
                                        break;

                                }

                                Canvas.SetLeft(tb, staticAge * widthRatio);
                                Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 5);
                                canvas.Children.Add(tb);
                            }
                        }
                    }

                    figure.Segments = new PathSegmentCollection { bezierSegment };

                    var pathCollection = new PathFigureCollection { figure };

                    var geometry = new PathGeometry(pathCollection);

                    var path = new Path();
                    path.Data = geometry;

                    if (j == 8)
                    {
                        path.StrokeThickness = 2;
                        path.Stroke = Brushes.ForestGreen;
                    }
                    else
                    {
                        path.StrokeThickness = 1.5;
                        path.Stroke = Brushes.Black;

                        if (j == 6 || j == 10) path.Stroke = Brushes.Gold;
                        if (j == 3 || j == 13) path.Stroke = Brushes.Tomato;
                    }

                    path.Width = canvas.ActualWidth;
                    path.Height = canvas.ActualHeight;

                    Canvas.SetLeft(path, 0);
                    Canvas.SetTop(path, 0);
                    canvas.Children.Add(path);
                }
            }
        }


        private void DrawWHO2006SDCurves()
        {
            PersonViewModel vm = DataContext as PersonViewModel;

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;

            if (vm != null && canvas != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));
                double[,] data = MaleWHO2006BMIData_SD;

                if (YAxisPath.ToString().Equals("BodyMassIndex"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006BMIData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006BMIData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("Height"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006HAData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006HAData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("Weight"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006WAData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006WAData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("HeadCircumference"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006HCData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006HCData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("MidUpperArmCircumference"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2006ACData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2006ACData_SD;
                    }
                }
                else
                {
                    return;
                }

                for (int j = 3; j < 8; j++)
                {
                    var figure = new PathFigure();

                    var bezierSegment = new PolyBezierSegment();

                    bool first = true;

                    for (int i = 0; i < (data.Length / 10) - 1; i++)
                    {
                        double staticAge = (data[i, 0] * 0.00273785);

                        if (staticAge >= (double)GetValue(XAxisStartValueProperty) && staticAge <= (double)GetValue(YAxisEndValueProperty))
                        {
                            staticAge = staticAge - XAxisStartValue;
                            double staticBodyMassIndex = data[i, j] - YAxisStartValue;

                            if (i == 0 || first)
                            {
                                figure.StartPoint = new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio));
                                first = false;
                            }

                            bezierSegment.Points.Add(new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio)));

                            if (YAxisPath.ToString().Equals("HeadCircumference") || YAxisPath.ToString().Equals("MidUpperArmCircumference"))
                            {
                                if (i == (data.Length / data.GetLength(1)) - 2)
                                {
                                    TextBlock tb = new TextBlock();
                                    tb.FontSize = 12;

                                    switch (j)
                                    {
                                        case 1:
                                            tb.Text = "-4";
                                            break;
                                        case 2:
                                            tb.Text = "-3";
                                            break;
                                        case 3:
                                            tb.Text = "-2";
                                            break;
                                        case 4:
                                            tb.Text = "-1";
                                            break;
                                        case 5:
                                            tb.Text = "0";
                                            break;
                                        case 6:
                                            tb.Text = "1";
                                            break;
                                        case 7:
                                            tb.Text = "2";
                                            break;
                                        case 8:
                                            tb.Text = "3";
                                            break;
                                        case 9:
                                            tb.Text = "4";
                                            break;
                                    }

                                    Canvas.SetLeft(tb, (staticAge * widthRatio) + 5);
                                    Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 4);
                                    canvas.Children.Add(tb);
                                }
                            }

                            //if (i == (data.Length / 10) - 2)
                            //{
                            //    var tb = new TextBlock { FontSize = 12 };

                            //    switch (j)
                            //    {
                            //        case 1:
                            //            tb.Text = "-4";
                            //            break;
                            //        case 2:
                            //            tb.Text = "-3";
                            //            break;
                            //        case 3:
                            //            tb.Text = "-2";
                            //            break;
                            //        case 4:
                            //            tb.Text = "-1";
                            //            break;
                            //        case 5:
                            //            tb.Text = "0";
                            //            break;
                            //        case 6:
                            //            tb.Text = "1";
                            //            break;
                            //        case 7:
                            //            tb.Text = "2";
                            //            break;
                            //        case 8:
                            //            tb.Text = "3";
                            //            break;
                            //        case 9:
                            //            tb.Text = "4";
                            //            break;

                            //    }

                            //    Canvas.SetLeft(tb, staticAge * widthRatio);
                            //    Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 5);
                            //    canvas.Children.Add(tb);
                            //}
                        }
                    }

                    figure.Segments = new PathSegmentCollection { bezierSegment };

                    var pathCollection = new PathFigureCollection { figure };

                    var geometry = new PathGeometry(pathCollection);

                    var path = new Path();
                    path.Data = geometry;

                    if (j == 5)
                    {
                        path.StrokeThickness = 2;
                        path.Stroke = Brushes.ForestGreen;
                    }
                    else
                    {
                        path.StrokeThickness = 1.5;
                        path.Stroke = Brushes.Black;

                        if (j == 4 || j == 6) path.Stroke = Brushes.Gold;
                        if (j == 3 || j == 7) path.Stroke = Brushes.Tomato;
                    }

                    path.Width = canvas.ActualWidth;
                    path.Height = canvas.ActualHeight;

                    Canvas.SetLeft(path, 0);
                    Canvas.SetTop(path, 0);
                    canvas.Children.Add(path);
                }
            }
        }

        private void DrawWHO2007SDCurves()
        {
            PersonViewModel vm = DataContext as PersonViewModel;

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;

            if (vm != null && canvas != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));
                double[,] data = MaleWHO2007BMIData_SD;

                if (YAxisPath.ToString().Equals("BodyMassIndex"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007BMIData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007BMIData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("Height"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007HAData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007HAData_SD;
                    }
                }
                else if (YAxisPath.ToString().Equals("Weight"))
                {
                    if (vm.Sex == "F")
                    {
                        data = FemaleWHO2007WAData_SD;
                    }
                    else if (vm.Sex == "M")
                    {
                        data = MaleWHO2007WAData_SD;
                    }
                }
                else
                {
                    return;
                }

                for (int j = 3; j < 8; j++)
                {
                    var figure = new PathFigure();

                    var bezierSegment = new PolyBezierSegment();

                    bool first = true;

                    for (int i = 0; i < (data.Length / 10) - 1; i++)
                    {
                        double staticAge = (data[i, 0] / 12);

                        if (staticAge >= (double)GetValue(XAxisStartValueProperty) && staticAge <= (double)GetValue(YAxisEndValueProperty))
                        {
                            staticAge = staticAge - XAxisStartValue;
                            double staticBodyMassIndex = data[i, j] - YAxisStartValue;

                            if (i == 0 || first)
                            {
                                figure.StartPoint = new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio));
                                first = false;
                            }

                            bezierSegment.Points.Add(new Point(staticAge * widthRatio, actualHeight - (staticBodyMassIndex * heightRatio)));

                            if (i == (data.Length / 10) - 2)
                            {
                                var tb = new TextBlock { FontSize = 12 };

                                switch (j)
                                {
                                    case 1:
                                        tb.Text = "-4";
                                        break;
                                    case 2:
                                        tb.Text = "-3";
                                        break;
                                    case 3:
                                        tb.Text = "-2";
                                        break;
                                    case 4:
                                        tb.Text = "-1";
                                        break;
                                    case 5:
                                        tb.Text = "0";
                                        break;
                                    case 6:
                                        tb.Text = "1";
                                        break;
                                    case 7:
                                        tb.Text = "2";
                                        break;
                                    case 8:
                                        tb.Text = "3";
                                        break;
                                    case 9:
                                        tb.Text = "4";
                                        break;

                                }

                                Canvas.SetLeft(tb, staticAge * widthRatio);
                                Canvas.SetTop(tb, actualHeight - (staticBodyMassIndex * heightRatio) - 5);
                                canvas.Children.Add(tb);
                            }
                        }
                    }

                    figure.Segments = new PathSegmentCollection { bezierSegment };

                    var pathCollection = new PathFigureCollection { figure };

                    var geometry = new PathGeometry(pathCollection);

                    var path = new Path();
                    path.Data = geometry;

                    if (j == 5)
                    {
                        path.StrokeThickness = 2;
                        path.Stroke = Brushes.ForestGreen;
                    }
                    else
                    {
                        path.StrokeThickness = 1.5;
                        path.Stroke = Brushes.Black;

                        if (j == 4 || j == 6) path.Stroke = Brushes.Gold;
                        if (j == 3 || j == 7) path.Stroke = Brushes.Tomato;
                    }

                    path.Width = canvas.ActualWidth;
                    path.Height = canvas.ActualHeight;

                    Canvas.SetLeft(path, 0);
                    Canvas.SetTop(path, 0);
                    canvas.Children.Add(path);
                }
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var canvas = this.GetTemplateChild("canvasMain") as Canvas;
            var canvasXAxis = this.GetTemplateChild("canvasXAxis") as Canvas;
            var canvasYAxis = this.GetTemplateChild("canvasYAxis") as Canvas;

            if (canvas != null && canvasXAxis != null && canvasYAxis != null)
            {
                double actualWidth = canvas.ActualWidth;
                double actualHeight = canvas.ActualHeight;

                double widthRatio = actualWidth / ((double)GetValue(XAxisEndValueProperty) - (double)GetValue(XAxisStartValueProperty));
                double heightRatio = actualHeight / ((double)GetValue(YAxisEndValueProperty) - (double)GetValue(YAxisStartValueProperty));

                canvas.Children.Clear();
                canvasXAxis.Children.Clear();
                canvasYAxis.Children.Clear();

                // add grid lines

                Color ultraLightGray = Color.FromRgb(238, 238, 238);
                SolidColorBrush ultraLightGrayBrush = new SolidColorBrush(ultraLightGray);
                ultraLightGrayBrush.Freeze();

                // minor grid lines
                if (ShowMinorGridLines)
                {
                    for (int k = (int)YAxisStartValue; k <= YAxisEndValue; k = k + (int)YAxisStepValue)
                    {
                        if ((double)k != YAxisEndValue)
                        {
                            for (double m = 0.2; m < 1.0; m = m + 0.2)
                            {
                                double indexMinor = (((double)k) + (m * YAxisStepValue)) - YAxisStartValue;

                                AddStaticLine(canvas, ultraLightGrayBrush, 0, canvas.ActualWidth, indexMinor * heightRatio, indexMinor * heightRatio);
                            }
                        }
                    }

                    for (int k = (int)Math.Round(XAxisStartValue); k <= XAxisEndValue; k++)
                    {
                        if ((double)k != XAxisEndValue)
                        {
                            for (double m = 0.2; m < 1.0; m = m + 0.2)
                            {
                                double indexMinor = (((double)k) + m) - XAxisStartValue;

                                AddStaticLine(canvas, ultraLightGrayBrush, indexMinor * widthRatio, indexMinor * widthRatio, 0, canvas.ActualHeight);
                            }
                        }
                    }
                }

                // major grid lines
                for (int k = (int)Math.Round(XAxisStartValue); k <= XAxisEndValue; k++)
                {
                    double index = (double)k - XAxisStartValue;

                    AddStaticLine(canvas, Brushes.LightGray, index * widthRatio, index * widthRatio, 0, canvas.ActualHeight);

                    TextBlock tb = new TextBlock();
                    tb.Text = k.ToString();
                    tb.FontSize = 10;

                    Canvas.SetTop(tb, 0);
                    if (k >= 10)
                    {
                        Canvas.SetLeft(tb, (index * widthRatio) - 5);
                    }
                    else
                    {
                        Canvas.SetLeft(tb, (index * widthRatio) - 3);
                    }

                    canvasXAxis.Children.Add(tb);
                }

                for (int k = (int)YAxisStartValue; k <= YAxisEndValue; k = k + (int)YAxisStepValue)
                {
                    double index = (double)k - YAxisStartValue;

                    AddStaticLine(canvas, Brushes.LightGray, 0, canvas.ActualWidth, index * heightRatio, index * heightRatio);

                    TextBlock tb = new TextBlock();
                    tb.Text = k.ToString();
                    tb.FontSize = 10;

                    Canvas.SetBottom(tb, (index * heightRatio) - 5);
                    Canvas.SetLeft(tb, 0);

                    canvasYAxis.Children.Add(tb);
                }

                string reference = GetValue(GrowthReferenceProperty).ToString();

                if (reference.Equals("CDC", StringComparison.OrdinalIgnoreCase))
                {
                    DrawCDCPercentileCurves();
                }
                else
                {
                    if (ShowsInPercentiles)
                    {
                        DrawWHO2006PercentileCurves();
                        DrawWHO2007PercentileCurves();
                    }
                    else
                    {
                        DrawWHO2006SDCurves();
                        DrawWHO2007SDCurves();
                    }
                }
            }
        }
    }
}

